/**
 *                            License
 * THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS  
 * CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). 
 * THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW.  
 * ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR  
 * COPYRIGHT LAW IS PROHIBITED.
 * 
 * BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND  
 * AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE  
 * MAY BE CONSIDERED TO BE A CONTRACT,
 * THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED 
 * HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
 * 
 */
package lineage.model.map;

import lineage.util.L1Heading;
import lineage.util.L1Point;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * V1地图.
 * 
 * @version 2014年4月5日下午3:43:03
 * @author jrwz
 */
public final class L1V1Map extends L1Map {
    private static final Logger LOG = LoggerFactory.getLogger(L1V1Map.class);
    /** 地图编号. */
    private int mapId;
    /** 坐标x：左上角. */
    private int topLeftX;
    /** 坐标y：左上角. */
    private int topLeftY;
    /** 坐标x：右下角. */
    private int bottomRightX;
    /** 坐标y：右下角. */
    private int bottomRightY;
    private byte[][] map;
    /** Mob不能通过. */
    private static final byte BITFLAG_IS_IMPASSABLE = (byte) 128;

    public L1V1Map() {
    }

    public L1V1Map(final int mapId, final byte[][] map, final int topLeftX, final int topLeftY) {
        this.mapId = mapId;
        this.map = map;
        this.topLeftX = topLeftX; // 起点X
        this.topLeftY = topLeftY; // 起点Y
        this.bottomRightX = topLeftX + map.length - 1; // 终点X
        this.bottomRightY = topLeftY + map[0].length - 1; // 终点Y
    }

    public L1V1Map(final L1V1Map map) {
        mapId = map.mapId;

        // map复制
        this.map = new byte[map.map.length][];
        for (int i = 0; i < map.map.length; i++) {
            this.map[i] = map.map[i].clone();
        }

        topLeftX = map.topLeftX;
        topLeftY = map.topLeftY;
        bottomRightX = map.bottomRightX;
        bottomRightY = map.bottomRightY;
    }

    @Override
    public int getMapId() {
        return mapId;
    }

    @Override
    public int getX() {
        return topLeftX;
    }

    @Override
    public int getY() {
        return topLeftY;
    }

    @Override
    public int getWidth() {
        return bottomRightX - topLeftX + 1;
    }

    @Override
    public int getHeight() {
        return bottomRightY - topLeftY + 1;
    }

    public byte[][] getRawTiles() {
        return map;
    }

    @Override
    public boolean isInMap(final int x, final int y) {
        // TODO 待定
        return ((x >= topLeftX) && (x <= bottomRightX) && (y >= topLeftY) && (y <= bottomRightY));
    }

    @Override
    public boolean isInMap(final L1Point pt) {
        return isInMap(pt.getX(), pt.getY());
    }

    private int accessTile(final int x, final int y) {
        if (!isInMap(x, y)) {
            return 0;
        }
        return map[x - topLeftX][y - topLeftY];
    }

    private int accessOriginalTile(final int x, final int y) {
        return accessTile(x, y) & (~BITFLAG_IS_IMPASSABLE);
    }

    private void setTile(final int x, final int y, final int tile) {
        if (!isInMap(x, y)) {
            return;
        }
        map[x - topLeftX][y - topLeftY] = (byte) tile;
    }

    @Override
    public int getTile(final int x, final int y) {
        final short tile = map[x - topLeftX][y - topLeftY];
        if (0 != (tile & BITFLAG_IS_IMPASSABLE)) {
            return 300;
        }
        return accessOriginalTile(x, y);
    }

    @Override
    public int getOriginalTile(int x, int y) {
        return accessOriginalTile(x, y);
    }

    /**
     * 门／
     */
    private void setDoor0(final int x, final int y, final boolean isPassable) {
        try {
            if (isPassable) { // 可通过
                map[x - topLeftX][y - topLeftY] = 0x2f;
            } else { // 不可通过
                map[x - topLeftX][y - topLeftY] = 0x03;
                map[(x - 1) - topLeftX][y - topLeftY] = 0x03;
                map[(x + 1) - topLeftX][y - topLeftY] = 0x03;
            }
        } catch (final Exception e) {
            LOG.error("门／ X：(" + x + ") Y：(" + y + ") MAP：(" + mapId + ")", e);
        }
    }

    /**
     * 门＼
     */
    private void setDoor1(final int x, final int y, final boolean isPassable) {
        try {
            if (isPassable) { // 可通过
                map[x - topLeftX][y - topLeftY] = 0x2f;
            } else { // 不可通过
                map[x - topLeftX][y - topLeftY] = 0x03;
                map[x - topLeftX][(y - 1) - topLeftY] = 0x03;
                map[x - topLeftX][(y + 1) - topLeftY] = 0x03;
            }
        } catch (final Exception e) {
            LOG.error("门＼ X：(" + x + ") Y：(" + y + ") MAP：(" + mapId + ")", e);
        }
    }

    @Override
    public void setPassable(final int x, final int y, final boolean isPassable, final int door) {
        switch (door) {
        case 0: // 0:门／
            setDoor0(x, y, isPassable);
            break;
        case 1: // 1:门＼
            setDoor1(x, y, isPassable);
            break;
        default:// 2:一般
            if (isPassable) {
                setTile(x, y, (short) (accessTile(x, y) & (~BITFLAG_IS_IMPASSABLE)));
            } else {
                setTile(x, y, (short) (accessTile(x, y) | BITFLAG_IS_IMPASSABLE));
            }
            break;
        }
    }

    @Override
    public void setPassable(final L1Point pt, final boolean isPassable) {
        setPassable(pt.getX(), pt.getY(), isPassable, 2);
    }

    @Override
    public boolean isPassable(final int x, final int y) {
        return isPassable(x, y - 1, 4) || isPassable(x + 1, y, 6) || isPassable(x, y + 1, 0) || isPassable(x - 1, y, 2);
    }

    @Override
    public boolean isPassable(final L1Point pt) {
        return isPassable(pt.getX(), pt.getY());
    }

    @Override
    public boolean isPassable(final int x, final int y, final int heading) {
        // 当前坐标
        final int tile1 = accessTile(x, y);
        final int locx = x + L1Point.HEADING_TABLE_X[heading];
        final int locy = y + L1Point.HEADING_TABLE_Y[heading];
        // 移动后的坐标
        final int tile2 = accessTile(locx, locy);
        if (tile2 == 0) {
            return false;
        }
        if ((tile2 & BITFLAG_IS_IMPASSABLE) == BITFLAG_IS_IMPASSABLE) {
            return false;
        }

        int tile3;
        int tile4;
        switch (heading) {
        case L1Heading.UP:
            return (tile1 & 0x02) == 0x02;
        case L1Heading.UP_RIGHT:
            tile3 = accessTile(x, y - 1);
            tile4 = accessTile(x + 1, y);
            return ((tile3 & 0x01) == 0x01) || ((tile4 & 0x02) == 0x02);
        case L1Heading.RIGHT:
            return (tile1 & 0x01) == 0x01;
        case L1Heading.DOWN_RIGHT:
            tile3 = accessTile(x, y + 1);
            return (tile3 & 0x01) == 0x01;
        case L1Heading.DOWN:
            return (tile2 & 0x02) == 0x02;
        case L1Heading.DOWN_LEFT:
            return ((tile2 & 0x01) == 0x01) || ((tile2 & 0x02) == 0x02);
        case L1Heading.LEFT:
            return (tile2 & 0x01) == 0x01;
        case L1Heading.UP_LEFT:
            tile3 = accessTile(x - 1, y);
            return (tile3 & 0x02) == 0x02;
        }
        return false;
    }

    @Override
    public boolean isPassable(final L1Point pt, final int heading) {
        return isPassable(pt.getX(), pt.getY(), heading);
    }

    @Override
    public boolean isNormalZone(final int x, final int y) {
        final int tile = accessOriginalTile(x, y);
        return (tile & 0x30) == 0x00;
    }

    @Override
    public boolean isNormalZone(final L1Point pt) {
        return isNormalZone(pt.getX(), pt.getY());
    }

    @Override
    public boolean isSafetyZone(final int x, final int y) {
        final int tile = accessOriginalTile(x, y);
        return (tile & 0x30) == 0x10;
    }

    @Override
    public boolean isSafetyZone(final L1Point pt) {
        return isSafetyZone(pt.getX(), pt.getY());
    }

    @Override
    public boolean isCombatZone(final int x, final int y) {
        final int tile = accessOriginalTile(x, y);
        return (tile & 0x30) == 0x20;
    }

    @Override
    public boolean isCombatZone(final L1Point pt) {
        return isCombatZone(pt.getX(), pt.getY());
    }

    @Override
    public boolean isArrowPassable(final int x, final int y) {
        return (accessOriginalTile(x, y) & 0x0e) != 0;
    }

    @Override
    public boolean isArrowPassable(final L1Point pt) {
        return isArrowPassable(pt.getX(), pt.getY());
    }

    @Override
    public boolean isArrowPassable(final int x, final int y, final int heading) {
        final int newX = x + L1Point.HEADING_TABLE_X[heading];
        final int newY = y + L1Point.HEADING_TABLE_Y[heading];
        // 移动后坐标
        final int tile2 = accessTile(newX, newY);
        boolean flag = false;
        switch (tile2) {
        case 0: // 不可通行
        case 3: // 关闭的门
            break;
        default: // 一般
            flag = (tile2 & 0x0c) != 0x00;
            break;
        }
        return flag;
    }

    @Override
    public boolean isArrowPassable(final L1Point pt, final int heading) {
        return isArrowPassable(pt.getX(), pt.getY(), heading);
    }

    @Override
    public String toString(final L1Point pt) {
        return "" + getOriginalTile(pt.getX(), pt.getY());
    }
}
